GHashTable *observed_actions;
GHashTable *groups;
+ GHashTable *primary_accels;
GtkActionMuxer *parent;
};
static GParamSpec *properties[NUM_PROPERTIES];
+guint accel_signal;
+
typedef struct
{
GtkActionMuxer *muxer;
gtk_action_muxer_action_removed (muxer, action_name);
}
+static void
+gtk_action_muxer_primary_accel_changed (GtkActionMuxer *muxer,
+ const gchar *action_name,
+ const gchar *action_and_target)
+{
+ Action *action;
+ GSList *node;
+
+ if (!action_name)
+ action_name = strrchr (action_and_target, '|') + 1;
+
+ action = g_hash_table_lookup (muxer->observed_actions, action_name);
+ for (node = action ? action->watchers : NULL; node; node = node->next)
+ gtk_action_observer_primary_accel_changed (node->data, GTK_ACTION_OBSERVABLE (muxer),
+ action_name, action_and_target);
+ g_signal_emit (muxer, accel_signal, 0, action_name, action_and_target);
+}
+
+static void
+gtk_action_muxer_parent_primary_accel_changed (GtkActionMuxer *parent,
+ const gchar *action_name,
+ const gchar *action_and_target,
+ gpointer user_data)
+{
+ GtkActionMuxer *muxer = user_data;
+
+ /* If it's in our table then don't let the parent one filter through */
+ if (muxer->primary_accels && g_hash_table_lookup (muxer->primary_accels, action_and_target))
+ return;
+
+ gtk_action_muxer_primary_accel_changed (muxer, action_name, action_and_target);
+}
+
static gboolean
gtk_action_muxer_query_action (GActionGroup *action_group,
const gchar *action_name,
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
+ g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_primary_accel_changed, muxer);
g_clear_object (&muxer->parent);
}
class->finalize = gtk_action_muxer_finalize;
class->dispose = gtk_action_muxer_dispose;
+ accel_signal = g_signal_new ("primary-accel-changed", GTK_TYPE_ACTION_MUXER, G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+
properties[PROP_PARENT] = g_param_spec_object ("parent", "Parent",
"The parent muxer",
GTK_TYPE_ACTION_MUXER,
return muxer->parent;
}
+static void
+emit_changed_accels (GtkActionMuxer *muxer,
+ GtkActionMuxer *parent)
+{
+ while (parent)
+ {
+ if (parent->primary_accels)
+ {
+ GHashTableIter iter;
+ gpointer key;
+
+ g_hash_table_iter_init (&iter, parent->primary_accels);
+ while (g_hash_table_iter_next (&iter, &key, NULL))
+ gtk_action_muxer_primary_accel_changed (muxer, NULL, key);
+ }
+
+ parent = parent->parent;
+ }
+}
+
/**
* gtk_action_muxer_set_parent:
* @muxer: a #GtkActionMuxer
gtk_action_muxer_action_removed (muxer, *it);
g_strfreev (actions);
+ emit_changed_accels (muxer, muxer->parent);
+
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
+ g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_primary_accel_changed, muxer);
g_object_unref (muxer->parent);
}
gtk_action_muxer_action_added (muxer, *it, G_ACTION_GROUP (muxer->parent), *it);
g_strfreev (actions);
+ emit_changed_accels (muxer, muxer->parent);
+
g_signal_connect (muxer->parent, "action-added",
G_CALLBACK (gtk_action_muxer_action_added_to_parent), muxer);
g_signal_connect (muxer->parent, "action-removed",
G_CALLBACK (gtk_action_muxer_parent_action_enabled_changed), muxer);
g_signal_connect (muxer->parent, "action-state-changed",
G_CALLBACK (gtk_action_muxer_parent_action_state_changed), muxer);
+ g_signal_connect (muxer->parent, "primary-accel-changed",
+ G_CALLBACK (gtk_action_muxer_parent_primary_accel_changed), muxer);
}
g_object_notify_by_pspec (G_OBJECT (muxer), properties[PROP_PARENT]);
}
+
+void
+gtk_action_muxer_set_primary_accel (GtkActionMuxer *muxer,
+ const gchar *action_and_target,
+ const gchar *primary_accel)
+{
+ if (!muxer->primary_accels)
+ muxer->primary_accels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ if (primary_accel)
+ g_hash_table_insert (muxer->primary_accels, g_strdup (action_and_target), g_strdup (primary_accel));
+ else
+ g_hash_table_remove (muxer->primary_accels, action_and_target);
+
+ gtk_action_muxer_primary_accel_changed (muxer, NULL, action_and_target);
+}
+
+const gchar *
+gtk_action_muxer_get_primary_accel (GtkActionMuxer *muxer,
+ const gchar *action_and_target)
+{
+ if (muxer->primary_accels)
+ {
+ const gchar *primary_accel;
+
+ primary_accel = g_hash_table_lookup (muxer->primary_accels, action_and_target);
+
+ if (primary_accel)
+ return primary_accel;
+ }
+
+ if (!muxer->parent)
+ return NULL;
+
+ return gtk_action_muxer_get_primary_accel (muxer->parent, action_and_target);
+}
+
+gchar *
+gtk_print_action_and_target (const gchar *action_namespace,
+ const gchar *action_name,
+ GVariant *target)
+{
+ GString *result;
+
+ g_return_if_fail (strchr (action_name, '|') == NULL);
+ g_return_if_fail (action_namespace == NULL || strchr (action_namespace, '|') == NULL);
+
+ result = g_string_new (NULL);
+
+ if (target)
+ g_variant_print_string (target, result, TRUE);
+ g_string_append_c (result, '|');
+
+ if (action_namespace)
+ {
+ g_string_append (result, action_namespace);
+ g_string_append_c (result, '.');
+ }
+
+ g_string_append (result, action_name);
+
+ return g_string_free (result, FALSE);
+}
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_removed (observer, observable, action_name);
}
+
+/**
+ * gtk_action_observer_primary_accel_changed:
+ * @observer: a #GtkActionObserver
+ * @observable: the source of the event
+ * @action_name: the name of the action
+ * @action_and_target: detailed action of the changed accel, in "action and target" format
+ *
+ * This function is called when an action that the observer is
+ * registered to receive events for has one of its accelerators changed.
+ *
+ * Accelerator changes are reported for all targets associated with the
+ * action. The @action_and_target string should be used to check if the
+ * reported target is the one that the observer is interested in.
+ */
+void
+gtk_action_observer_primary_accel_changed (GtkActionObserver *observer,
+ GtkActionObservable *observable,
+ const gchar *action_name,
+ const gchar *action_and_target)
+{
+ GtkActionObserverInterface *iface;
+
+ g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
+
+ iface = GTK_ACTION_OBSERVER_GET_IFACE (observer);
+
+ if (iface->primary_accel_changed)
+ iface->primary_accel_changed (observer, observable, action_name, action_and_target);
+}